/* Copyright (c) 2008 Charles Rich and Worcester Polytechnic Institute.
 * All Rights Reserved.  Use is subject to license terms.  See the file
 * "license.terms" for information on usage and redistribution of this
 * file and for a DISCLAIMER OF ALL WARRANTIES.
 */
package edu.wpi.cetask.guide;

import java.io.*;
import java.net.*;

import javax.speech.recognition.*;

import edu.cmu.sphinx.util.props.*;
import edu.cmu.sphinx.frontend.util.Microphone;
import edu.cmu.sphinx.jsapi.JSGFGrammar;
import edu.cmu.sphinx.recognizer.Recognizer;
import edu.cmu.sphinx.result.Result;
import edu.wpi.cetask.Utils;

public class Sphinx4 implements SpeechGuide.Recognizer {
   
   private Recognizer recognizer;
   private Microphone microphone;
   private JSGFGrammar jsgf;
   private RuleGrammar rules;
   
   Sphinx4 () {
      try {
         ConfigurationManager cm = new ConfigurationManager(
               Sphinx4.class.getResource("guide.config.xml"));
         recognizer = (Recognizer) cm.lookup("recognizer");
         microphone = (Microphone) cm.lookup("microphone");
         recognizer.allocate();
         jsgf = (JSGFGrammar) cm.lookup("jsgfGrammar"); 
         rules = jsgf.getRuleGrammar();
      } catch (Exception e) { Guide.exception(e); }
   }
       
   // implementation of Recognizer interface

   public String recognize () { 
      // assuming automatic endpointing and that 'closeBetweenUtterances' property 
      // of microphone component is set to "false" in config file
      microphone.clear();
      microphone.startRecording();
      Result result = recognizer.recognize();
      // TODO following causes exception on Mac (audio line running)
      // but it's absence may cause memory overflow if running long between ptt's
      // microphone.startRecording();
      return result == null ? null : result.getBestFinalResultNoFiller();
   }

   public Object interpret (String utterance) {
      RuleParse parse = null;
      try { parse = rules.parse(utterance, null); } 
      catch (GrammarException e) { Guide.exception(e); }
      if ( parse == null ) return null;
      String[] tags = parse.getTags();
      if ( tags == null ) return null;
      StringBuffer buffer = new StringBuffer();
      for (int i = 0; i < tags.length; i++) { 
         if ( i > 0 ) buffer.append(' ');
         buffer.append(tags[i].trim());
      }
      return buffer.toString();
   }
   
   public void loadGrammar (String uri) throws IOException {
      String spec = Utils.toURL(uri).toExternalForm();
      int i = spec.lastIndexOf('/');
      jsgf.setBaseURL(new URL(spec.substring(0, i)));
      jsgf.loadJSGF(spec.substring(i, spec.length()-5));
      rules = jsgf.getRuleGrammar();
   }
   
   public void deallocate () { 
      recognizer.deallocate(); 
      microphone.stopRecording();
   }

}
